﻿using System;
using System.IO;
using System.IO.Pipes;
using System.Threading;

namespace PipeUtil.Pipe
{
    public class PipeServer
    {
        private bool _running;
        private Thread _runningThread;
        private readonly EventWaitHandle _terminateHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
        private readonly IBusinessDelegate _businessDelegate;
        public string PipeName { get; private set; }


        public PipeServer(string pipeName, IBusinessDelegate businessDelegate)
        {
            _businessDelegate = businessDelegate;
            PipeName = pipeName;
        }

        private void ServerLoop()
        {
            while (_running)
            {
                ProcessNextClient();
            }
            _terminateHandle.Set();
        }

        public void Start()
        {
            _running = true;
            _runningThread = new Thread(ServerLoop);
            _runningThread.Start();
        }

        public void Stop()
        {
            _running = false;
            _terminateHandle.WaitOne();
        }

        private void ProcessClientThread(object o)
        {
            var pipeStream = (NamedPipeServerStream) o;

            try
            {
                var streamStringServer = new StreamString(pipeStream);
                var request = streamStringServer.ReadString();
                var response = _businessDelegate.SendRequest(request);
                streamStringServer.WriteString(response);
            }
            catch (IOException e)
            {
                Console.WriteLine("ERROR: {0}\n", e.Message);
            }

            pipeStream.Close();
            pipeStream.Dispose();
        }

        private void ProcessNextClient()
        {
            try
            {
                var pipeStream = new NamedPipeServerStream(PipeName, PipeDirection.InOut);
                pipeStream.WaitForConnection();
                var t = new Thread(ProcessClientThread);
                t.Start(pipeStream);
            }
            catch (Exception e)
            {
                //If there are no more avail connections (254 is in use already) then just keep looping until one is avail
            }
        }
    }
}
